﻿using System;
using System.Threading;
using Sustainalytics.Admin.CRMSynchronization.Utility;
using Sustainalytics.Utils;

namespace Sustainalytics.Admin.CRMSynchronization
{
    public class Synchronization : ISync
    {
        private static ISync _synchronizer;
        private static Timer _syncChecker;
        private static IAccountsSync _accountsSync;
        private static IUsersSync _usersSync;
        private static IClaimsSync _claimsSync;
        private static TimeSpan _syncInterval;
        private static bool _isSynchronizing;
        private const string _errorMessagePlaceholder = "ERROR_MESSAGE";
        private const string _errorEmailSubjectFileName = "ErrorEmailSubject.txt";
        private const string _errorEmailBodyFileName = "ErrorEmailBody.htm";

        private Synchronization() { } // prohibit public instantiation

        public static ISync GetInstance(IAccountsSync accountsSync, IUsersSync usersSync, IClaimsSync claimsSync, TimeSpan syncInterval)
        {
            if (_synchronizer == null)
            {
                if (accountsSync == null)
                {
                    throw new ArgumentException("An instance of type IAccountsSync is needed in order to create an ISync instance!");    
                }

                if (usersSync == null)
                {
                    throw new ArgumentException("An instance of type IUsersSync is needed in order to create an ISync instance!");
                }

                if (claimsSync == null)
                {
                    throw new ArgumentException("An instance of type IClaimsSync is needed in order to create an ISync instance!");
                }

                _accountsSync = accountsSync;
                _usersSync = usersSync;
                _claimsSync = claimsSync;
                _syncInterval = syncInterval;

                _synchronizer = new Synchronization();
            }
            
            return _synchronizer;
        }

        public void Start()
        {
            if (_syncChecker == null)
            {
                _syncChecker = new Timer(Synchronize, null, TimeSpan.Zero, _syncInterval);
            }
        }

        private static void Synchronize(object timerState)
        {
            if (!_isSynchronizing)
            {
                try
                {
                    _isSynchronizing = true;

                    CrmSyncEventSource.SetCurrentThreadActivityId(Guid.NewGuid());

                    _accountsSync.SyncAccounts();

                    _usersSync.SyncUsers();

                    _claimsSync.SyncClaims();
                }
                catch (Exception e)
                {
                    CrmSyncEventSource.Log.SyncFailed(e.GetType().ToString(), e.Message, ExceptionUtility.GetInfo(e));
                    SendEmail(e);
                }
                finally
                {
                    _isSynchronizing = false;
                }
            }
        }
        private static void SendEmail(Exception ex)
        {
            try
            {
                var emailManager = new EmailManager(_errorEmailSubjectFileName, _errorEmailBodyFileName);
                emailManager.AddPlaceholderValue(_errorMessagePlaceholder, ex.Message + "<br/><br/>" + ex.StackTrace.Replace("\r\n", "<br/>"));
                emailManager.SendEmail();
            }
            catch
            {
                //nothing to do if we cannot send the email with the exception
            }
        }
    }
}
